#!/usr/bin/python
# -*- coding: utf-8 -*-

from trivmoo.utils.decorators import synchronized
from threading import Lock
import unittest
import time
from trivmoo.architectural_patterns.pools.thread_pool import ITask, BasicTaskQueue, ThreadPool


SINGLETON_LOCK = Lock()

# synchronized singleton
def synchronized_singleton(cls):
    instances = {}
    @synchronized(SINGLETON_LOCK)
    def get_instance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return get_instance

@synchronized_singleton
class TestSingletonClass(object):
    def __init__(self):
        self.__string = ''    
    def set_string(self, a_string):
        self.__string = a_string        
    def get_string(self):
        return self.__string
    
class TestTask(ITask):
    def __init__(self):
        ITask.__init__(self)
        self.__singleton = None
    def execute(self):
        self.__singleton = TestSingletonClass()
        self.__singleton.set_string('test')
        time.sleep(2)
    def get_singleton(self):
        return self.__singleton
    
class TestSingleton(unittest.TestCase):
    def test_creation(self):
        """TestSingleton: creation test"""
        oo1 = TestSingletonClass()
        oo2 = TestSingletonClass()
        oo3 = TestSingletonClass()        
        self.assertEqual(oo1, oo2)
        self.assertEqual(oo1, oo3)
        self.assertEqual(oo3, oo2)
    
    def test_set_and_get(self):
        """TestSingleton: get and set"""
        oo1 = TestSingletonClass()
        oo2 = TestSingletonClass()
        oo3 = TestSingletonClass()
        oo1.set_string("oo1")
        oo2.set_string("oo2")
        oo3.set_string("oo3")
        self.assertEqual(oo1.get_string(), oo2.get_string())
        self.assertEqual(oo1.get_string(), oo3.get_string())
        self.assertEqual(oo3.get_string(), oo2.get_string())
        
    def test_in_multithreading(self):
        """Multithreading test"""
        basic_queue = BasicTaskQueue()
        list_task = []
        for i in range(10):
            list_task.append(TestTask())
        
        for task in list_task:
            basic_queue.add_task(task)
            
        the_thread_pool = ThreadPool(200, basic_queue)
        
        the_thread_pool.start_pool()
        
        while not basic_queue.is_empty():
            time.sleep(1)
            
        the_thread_pool.stop_pool()
        the_singleton = TestSingletonClass()
        self.assertEqual(the_singleton.get_string(),'test')
        
        for task in list_task:
            self.assertEqual(the_singleton, task.get_singleton())   

if __name__ == "__main__":
    unittest.main()
